package io.renren.common.utils.image;


import com.sun.imageio.plugins.jpeg.JPEGImageReader;
import io.renren.modules.oss.cloud.OSSFactory;
import io.renren.modules.sp.entity.ContentEntity;

import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.util.Iterator;

import org.apache.commons.imaging.ImageReadException;
import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.common.ImageBuilder;
import org.apache.commons.imaging.common.ImageMetadata;
import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
import org.apache.commons.imaging.formats.tiff.TiffField;
import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
import org.apache.commons.io.IOUtils;

/**
 * 操作图片工具类
 * author: 峰影
 **/
public class DrawImageUtil {

    /**
     * @param image   原图
     * @param content 内容对象
     * @return void
     * @Description 向图片中填充内容
     * @Author 峰影
     */
    public static void drawContentEntity(BufferedImage image, ContentEntity content) throws Exception {

        int imgWidth = image.getWidth();
        int imgHeight = image.getHeight();

        // 根据百分比计算画笔开始位置的坐标
        BigDecimal x = new BigDecimal(content.getWidthPer() * imgWidth).setScale(4,
                BigDecimal.ROUND_HALF_UP);

        BigDecimal y = new BigDecimal(content.getHeightPer() * imgHeight).setScale(4,
                BigDecimal.ROUND_HALF_UP);

        Graphics2D g = (Graphics2D) image.getGraphics();
        if (!content.isImg()) {
            // 填充文字 从左往右
            DrawImageUtil.setStringToImg(content.getContent(), g,
                    x.intValue(), y.intValue(),
                    content.getFontFamily(),
                    content.getFontStyle(),
                    content.getFontSize(),
                    content.getFontSpace(),
                    content.getFontColor(),
                    content.getFontDirection());
        } else {
            // 填充图片
            URL url = new URL(content.getContent());
            //ImageIO.read(url);
            try{
            DrawImageUtil.mergePendant(g, ImageIO.read(url),
                    x.intValue(), y.intValue(), content.getImgWidth(), content.getImgHeight(), 1);
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }

    /**
     * 读取cmyk 图片
     * @param url
     * @return
     * @throws Exception
     */
    public static BufferedImage readCMYKImage(URL url) throws Exception {
        try (InputStream is = url.openStream()) {
            // 1. 使用ImageIO读取原始数据
            BufferedImage cmykImage = ImageIO.read(is);

            // 2. 获取原始图像数据
            int width = cmykImage.getWidth();
            int height = cmykImage.getHeight();

            // 3. 创建目标RGB图像
            BufferedImage rgbImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            // 4. 手动转换每个像素
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    int cmykPixel = cmykImage.getRGB(x, y);
                    int rgbPixel = cmykToRgb(cmykPixel);
                    rgbImage.setRGB(x, y, rgbPixel);
                }
            }

            return rgbImage;
        }
    }

    private static int cmykToRgb(int cmyk) {
        // 提取CMYK分量（假设是32位INT存储的CMYK）
        int c = (cmyk >> 24) & 0xFF;
        int m = (cmyk >> 16) & 0xFF;
        int y = (cmyk >> 8) & 0xFF;
        int k = cmyk & 0xFF;

        // CMYK到RGB转换公式
        int r = 255 - Math.min(255, c * (255 - k) / 255 + k);
        int g = 255 - Math.min(255, m * (255 - k) / 255 + k);
        int b = 255 - Math.min(255, y * (255 - k) / 255 + k);

        // 组合RGB值
        return (r << 16) | (g << 8) | b;
    }


    /**
     * 校正图片的 EXIF 方向
     * @param image     原始图片
     * @param imageBytes 图片字节数据（用于读取 EXIF）
     * @return 校正后的 BufferedImage
     */
    public static BufferedImage correctImageOrientation(BufferedImage image, byte[] imageBytes) {
        try {
            ImageMetadata metadata = Imaging.getMetadata(imageBytes);
            if (metadata instanceof JpegImageMetadata) {
                JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;

                TiffField orientationField = jpegMetadata.findEXIFValueWithExactMatch(TiffTagConstants.TIFF_TAG_ORIENTATION);
                Integer orientation = null;
                if(orientationField !=null){
                    orientation = orientationField.getIntValue();
                }

                if (orientation != null && orientation > 1) {
                    AffineTransform transform = new AffineTransform();
                    switch (orientation) {
                        case 3: // 180°
                            transform.rotate(Math.PI, image.getWidth() / 2.0, image.getHeight() / 2.0);
                            break;
                        case 6: // 90°
                            transform.rotate(Math.PI / 2, image.getWidth() / 2.0, image.getHeight() / 2.0);
                            transform.translate(0, -image.getWidth());
                            break;
                        case 8: // 270°
                            transform.rotate(3 * Math.PI / 2, image.getWidth() / 2.0, image.getHeight() / 2.0);
                            transform.translate(-image.getHeight(), 0);
                            break;
                        default:
                            return image;
                    }

                    BufferedImage rotated = new BufferedImage(
                            orientation == 6 || orientation == 8 ? image.getHeight() : image.getWidth(),
                            orientation == 6 || orientation == 8 ? image.getWidth() : image.getHeight(),
                            image.getType()
                    );
                    Graphics2D g2d = rotated.createGraphics();
                    g2d.drawImage(image, transform, null);
                    g2d.dispose();
                    return rotated;
                }
            }
        } catch (ImageReadException | IOException e) {
            e.printStackTrace(); // 日志记录或回退到原图
        }
        return image;
    }


    /**
     * @param image         -  BufferedImage对象
     * @param targetImgPath - 目标文件路径
     * @param suffix        - 文件格式
     * @return void
     * @Description 把图片无损再次保存
     * @Author 峰影
     **/
    public static String saveLossLessImage(BufferedImage image, String targetImgPath, String suffix) throws Exception {
        //不压缩图片质量进行保存
        ImageWriter writer = ImageIO.getImageWritersBySuffix(suffix).next();
        ImageWriteParam imageWriteParam = writer.getDefaultWriteParam();
        imageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        //0-1范围 越大质量越高
        imageWriteParam.setCompressionQuality(0.9f);
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        writer.setOutput(new MemoryCacheImageOutputStream(output));
        writer.write(null, new IIOImage(image, null, null), imageWriteParam);
        writer.dispose();

        //最终图片保存到本地
        /*FileOutputStream file = new FileOutputStream(targetImgPath);
        file.write(output.toByteArray());
        file.close();
        return null;*/


        //上传到oss
        String extension =  "jpg";
        String url = OSSFactory.build().uploadSuffix(imageToBytes(image, "jpg"), extension);
        output.close();
        return url;

    }

    /**
     * @param content    - 内容
     * @param g          - Graphics2D对象
     * @param x          - 坐标
     * @param y          - 坐标
     * @param fontFamily - 字体
     * @param fontStyle  - 字体样式
     * @param fontSize   - 字体大小
     * @param fontSpace  - 字体间距
     * @param fontColor  - 字体颜色
     * @return void
     * @Description 填充文字内容从左往右
     * @Author 峰影
     **/
    public static void setStringToImg(String content, Graphics2D g, Integer x, Integer y, String fontFamily,
                                      Integer fontStyle, Integer fontSize, Integer fontSpace, Color fontColor, Integer fontDirection) {
        Font font = new Font(fontFamily, fontStyle, fontSize);
        if (null == fontSpace) {
            //每个字的间距 默认用字体大小来分割
            fontSpace = fontSize;
        }
        System.out.println(content);
        // 判断content字符串,从第几位开始是数字类型
        /*int numIndex = 0;
        for (int i = 0; i < content.length(); i++) {
            if (content.charAt(i)=='-') {
                numIndex = i;
                break;
            }
        }*/
        // 判断content字符串,从第几位开始是数字类型
        int numIndex = content.indexOf("-");
        boolean isNumber = false;
        // 判断-后面是否全是数字
        if(numIndex > 0) {
            String num = content.substring(content.indexOf("-") + 1);
            isNumber = num.matches("[0-9]+");
        }

        for (int i = 0; i < content.length(); i++) {
            char singleWordChart = content.charAt(i);
            // 如果遇到·符号，字体换成宋体
            if (singleWordChart == '·') {
                font = new Font("宋体", fontStyle, fontSize);
            }else{
                font = new Font(fontFamily, fontStyle, fontSize);
            }
            AttributedString singleWord = new AttributedString(String.valueOf(singleWordChart));
            g.setStroke(new BasicStroke(2.5f));
            g.setColor(fontColor);
            g.setFont(font);
            /* 消除java.awt.Font字体的锯齿 */
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);
            /* 消除java.awt.Font字体的锯齿 */
            singleWord.addAttribute(TextAttribute.FONT, font, 0,
                    String.valueOf(singleWordChart).length());
            AttributedCharacterIterator singleWordIterator = singleWord.getIterator();

            Integer newX = x;
            Integer newY = y;
            //从左往右
            if(fontDirection == 0){
                if (i > 0) {
                    newX = x + (i * fontSpace);
                    //特殊符号间距处理
                    if(singleWordChart == '/' || singleWordChart == '-'){
                        newX = x + (i * fontSpace) + (fontSize/4);
                    }
                    if(singleWordChart == '·'){
                        newX = x + (i * fontSpace) + (fontSize/48);
                    }
                    // 从引号后的字符开始的第一个字符往后增加间距
                    if(content.contains("”")){
                        int speX = content.indexOf("”");
                        if(i > speX){
                            newX = x + ((speX * fontSpace) + ((i - speX) * (int)(fontSpace))) + fontSize/4;
                        }
                    }
                    // 判断是数字，间距使用26
                    if(numIndex > 0 && isNumber && i >= numIndex) {
                        //数字前的中文使用fontSpace作为间距, 从第一位数字开始使用18
                        newX = x + ((numIndex * fontSpace) + ((i - numIndex) * (int)(fontSpace*0.667)));
                    }
                    //证书编码里的第2位置处理
                    if(singleWordChart=='D' || singleWordChart == 'A'){
                        newX = newX - 4;
                    }
                    //参赛证里的（）处理
                    if(singleWordChart=='（' ){
                        newX = newX - 8;
                    }
                    if(singleWordChart=='）' ){
                        newX = newX + 6;
                    }
                    // “”引号的处理
                    if(singleWordChart=='“' || singleWordChart == '”'){
                        newX = newX + fontSize/2;
                    }

                    //证书编码里的第17位置处理
                    if(i==16 && singleWordChart=='G'){
                        // 往左移动一点
                        newX = newX - 12;
                    }
                    if(singleWordChart==':'){
                        // 往右移动一点
                        newX = newX + 12;
                    }

                }
                g.drawString(singleWordIterator, newX, y);
            }
            //从上往下
            if(fontDirection == 1){
                if (i > 0) {
                    newY = y + (i * fontSpace);
                }
                g.drawString(singleWordIterator, x, newY);
            }
        }
    }

    /**
     * @param g2d          底图
     * @param pendantImage 挂件图
     * @param x            距离左上角的X偏移量
     * @param y            距离左上角的Y偏移量
     * @param alpha        透明度, 选择值从0.0~1.0: 完全透明~完全不透明
     * @return void
     * @Description 两张图片合并为一张图片
     * @Author 峰影
     */
    public static void mergePendant(Graphics2D g2d, BufferedImage pendantImage, int x, int y, int w, int h, float alpha) {
        try {
            //获取挂件图像的宽高
            //int pendantImageWidth = pendantImage.getWidth();
            //int pendantImageHeight = pendantImage.getHeight();
            //int pendantImageWidth = 360;
            //int pendantImageHeight = 500;

            // 转换为字节数组以读取 EXIF
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(pendantImage, "jpg", baos);
            byte[] imageBytes = baos.toByteArray();

            // 校正方向
            /*BufferedImage correctedImage = correctImageOrientation(
                    ImageIO.read(new ByteArrayInputStream(imageBytes)),
                    imageBytes
            );*/

            int pendantImageWidth = w;
            int pendantImageHeight = h;
            //实现混合和透明效果
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
            //绘制图像
            g2d.drawImage(pendantImage, x, y, pendantImageWidth, pendantImageHeight, null);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    /**
     * 转换BufferedImage 数据为byte数组
     *
     * @param image
     * Image对象
     * @param format
     * image格式字符串.如"jpg","png"
     * @return byte数组
     */
    public static byte[] imageToBytes(BufferedImage bImage, String format) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            ImageIO.write(bImage, format, out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }
}
